package com.example.location_library.china_location

import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.baidu.location.BDAbstractLocationListener
import com.baidu.location.BDLocation
import com.baidu.location.LocationClient
import com.baidu.location.LocationClientOption
import com.tencent.map.geolocation.TencentLocation
import com.tencent.map.geolocation.TencentLocationListener
import com.tencent.map.geolocation.TencentLocationManager
import com.tencent.map.geolocation.TencentLocationRequest
/**
 * 版权：渤海新能 版权所有
 *
 * @author feiWang
 * 版本：1.5
 * 创建日期：2020/10/10
 * 描述：OsmDroid
 * CSDN:https://blog.csdn.net/m0_37667770/article
 * GitHub:https://github.com/luhenchang
 */
class ChinaLocation private constructor() : AMapLocationListener {
    private var chinaLocationNChange: ChinaLocationNotifyChange? = null

    ///高德地图
    //声明AMapLocationClient类对象
    var mLocationClient: AMapLocationClient? = null

    //声明定位回调监听器
    var mLocationOption = AMapLocationClientOption()


    //百度
    var mLocationClientbaidu: LocationClient? = null
    var myListener: MyLocationListener = MyLocationListener()


    //腾讯
    var listener: TencentLocationListener? = null
    var locationManager: TencentLocationManager? = null
    var request: TencentLocationRequest? = null
    var errorTx = 0
    lateinit var mcontext: Context
    var type: LocationType = LocationType.ALL

    companion object {
        @SuppressLint("StaticFieldLeak")
        private var mInstance: ChinaLocation? = null
            get() {
                if (field == null) {
                    field = ChinaLocation()
                }
                return field
            }

        @JvmStatic
        @Synchronized//添加synchronized同步锁
        fun getInstance(): ChinaLocation {
            return mInstance!!
        }
    }

    fun setContext(context: Context): ChinaLocation {
        this.mcontext = context
        this.chinaLocationNChange = context as ChinaLocationNotifyChange
        return this
    }

    fun setLocationType(type: LocationType): ChinaLocation {
        this.type = type
        return this
    }

    fun initLocation() {
        if (type == LocationType.GAO_DE) {
            initGaoDe()
        }

        if (type == LocationType.BAI_DU) {
            initBaiDu()
        }

        if (type == LocationType.TEN_XUN) {
            initTenXun()
        }

        if (type == LocationType.ALL) {
            initGaoDe()
            initBaiDu()
            initTenXun()
        }
    }

    private fun initTenXun() {
        ///腾讯定位
        listener = MyTencentLocationListener()
        request = TencentLocationRequest.create()

        locationManager = TencentLocationManager.getInstance(mcontext)

        errorTx = locationManager!!.requestLocationUpdates(request, listener)
    }

    private fun initBaiDu() {
        ///百度
        mLocationClientbaidu = LocationClient(mcontext.applicationContext)
        //声明LocationClient类
        mLocationClientbaidu?.registerLocationListener(myListener)
        //注册监听函数
        val option = LocationClientOption()
        option.locationMode = LocationClientOption.LocationMode.Hight_Accuracy
        //可选，设置定位模式，默认高精度
        //LocationMode.Hight_Accuracy：高精度；
        //LocationMode. Battery_Saving：低功耗；
        //LocationMode. Device_Sensors：仅使用设备；
        option.setCoorType("GCJ02")
        //可选，设置返回经纬度坐标类型，默认GCJ02
        //GCJ02：国测局坐标；（火星坐标）
        //BD09ll：百度经纬度坐标；
        //BD09：百度墨卡托坐标；
        //海外地区定位，无需设置坐标类型，统一返回WGS84类型坐标
        option.setScanSpan(1000)
        //可选，设置发起定位请求的间隔，int类型，单位ms
        //如果设置为0，则代表单次定位，即仅定位一次，默认为0
        //如果设置非0，需设置1000ms以上才有效
        option.isOpenGps = true
        //可选，设置是否使用gps，默认false
        //使用高精度和仅用设备两种定位模式的，参数必须设置为true
        option.isLocationNotify = true
        //可选，设置是否当GPS有效时按照1S/1次频率输出GPS结果，默认false
        option.setIgnoreKillProcess(false)
        //可选，定位SDK内部是一个service，并放到了独立进程。
        //设置是否在stop的时候杀死这个进程，默认（建议）不杀死，即setIgnoreKillProcess(true)
        option.SetIgnoreCacheException(false)
        //可选，设置是否收集Crash信息，默认收集，即参数为false
        option.setWifiCacheTimeOut(5 * 60 * 1000)
        //可选，V7.2版本新增能力
        //如果设置了该接口，首次启动定位时，会先判断当前Wi-Fi是否超出有效期，若超出有效期，会先重新扫描Wi-Fi，然后定位
        option.setEnableSimulateGps(false)
        //可选，设置是否需要过滤GPS仿真结果，默认需要，即参数为false
        option.setNeedNewVersionRgc(true)
        //可选，设置是否需要最新版本的地址信息。默认不需要，即参数为false
        mLocationClientbaidu?.locOption = option
        //mLocationClient为第二步初始化过的LocationClient对象
        //需将配置好的LocationClientOption对象，通过setLocOption方法传递给LocationClient对象使用
        //更多LocationClientOption的配置，请参照类参考中LocationClientOption类的详细说明
        mLocationClientbaidu?.start()
        //mLocationClient为第二步初始化过的LocationClient对象
        //调用LocationClient的start()方法，便可发起定位请求
    }

    private fun initGaoDe() {
        ///高德 默认 GCJ02
        mLocationClient = AMapLocationClient(mcontext.applicationContext)
        mLocationOption.locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy
        mLocationOption.interval = 2000
        mLocationOption.isNeedAddress = true
        mLocationOption.isMockEnable = true
        mLocationOption.httpTimeOut = 1000
        //给定位客户端对象设置定位参数
        mLocationClient?.setLocationOption(mLocationOption)
        //启动定位
        mLocationClient?.startLocation()
        //初始化定位
        //设置定位回调监听
        mLocationClient?.setLocationListener(this)
    }

    ///关闭所有的定位
    fun close() {
        //关闭高德
        if (mLocationClient != null) {
            mLocationClient?.unRegisterLocationListener(this)
            mLocationClient?.stopLocation()
        }
        //关闭百度
        if (mLocationClientbaidu != null) {
            mLocationClientbaidu?.unRegisterLocationListener(myListener)
            mLocationClientbaidu?.stop()
        }
        //关闭腾讯
        if (locationManager != null && listener != null) {
            locationManager?.removeUpdates(listener)
            listener = null
        }

    }

    ///关闭百度
    fun closeBd(): ChinaLocation {
        if (mLocationClientbaidu != null) {
            mLocationClientbaidu?.stop()
            mLocationClient = null
        }
        return this
    }

    ///关闭百度
    fun closeGd(): ChinaLocation {
        if (mLocationClient != null) {
            mLocationClient?.stopLocation()
            mLocationClient = null
        }
        return this
    }

    ///关闭腾讯
    fun closeTx(): ChinaLocation {
        if (locationManager != null && listener != null) {
            locationManager?.removeUpdates(listener)
            listener = null
        }
        return this
    }

    //百度定位
    inner class MyLocationListener : BDAbstractLocationListener() {
        override fun onReceiveLocation(location: BDLocation) {
            //此处的BDLocation为定位结果信息类，通过它的各种get方法可获取定位相关的全部结果
            //以下只列举部分获取经纬度相关（常用）的结果信息
            //更多结果信息获取说明，请参照类参考中BDLocation类中的说明
            Log.e("MainActivity", "gaocheng====: " + location.altitude)
            Log.e("MainActivity", "BaiduOnReceiveLocation: " + location.altitude + location.toString() + location.address.toString())
            //获取经纬度坐标类型，以LocationClientOption中设置过的坐标类型为准
            //获取定位类型、定位错误返回码，具体信息可参照类参考中BDLocation类中的说明
            ////室内定位
            //此处的BDLocation为定位结果信息类，通过它的各种get方法可获取定位相关的全部结果
            if (location.floor != null) {
                // 当前支持高精度室内定位
                val buildingID = location.buildingID // 百度内部建筑物ID
                val buildingName = location.buildingName // 百度内部建筑物缩写
                val floor = location.floor // 室内定位的楼层信息，如 f1,f2,b1,b2
                Log.e("百度位置", "onReceiveLocation: $floor$buildingID$buildingName")
                mLocationClientbaidu?.startIndoorMode() // 开启室内定位模式（重复调用也没问题），开启后，定位SDK会融合各种定位信息（GPS,WI-FI，蓝牙，传感器等）连续平滑的输出定位结果；
            }
            ////离线定位
            //此处的BDLocation为定位结果信息类，通过它的各种get方法可获取定位相关的全部结果
            if (location.locType == BDLocation.TypeOffLineLocation) {
                // 离线定位成功
                Log.i("baidu_location_result", "offline location success")
            } else if (location.locType == BDLocation.TypeOffLineLocationFail) {
                // 离线定位失败
                Log.i("baidu_location_result", "offline location fail")
            } else {
                Log.i("baidu_location_result", "location type = " + location.locType)
            }
            val chineLocationBean = ChineLocationBean()
            if (location.adCode != null) {
                chineLocationBean.chinaAdCode = location.adCode
            } else {
                chineLocationBean.chinaAdCode = ""
            }
            if (location.address.address != null) {
                chineLocationBean.chinaAddress = location.address.address
            } else {
                chineLocationBean.chinaAddress = ""
            }
            chineLocationBean.chinaAoiName = location.address.town
            chineLocationBean.chinaCity = location.city
            chineLocationBean.chinaCityCode = location.cityCode
            chineLocationBean.chinaDistrict = location.district
            chineLocationBean.chinaErrorCode = 0
            chineLocationBean.chinaRaduis= location.radius
            chineLocationBean.chinaDirection=location.direction;
            chineLocationBean.chinaFloor = location.floor
            chineLocationBean.chinaRoad = location.roadLocString
            chineLocationBean.chinaStreet = location.street
            chineLocationBean.chinaStreetNumber = location.streetNumber
            chineLocationBean.chinaProvince = location.province
            chineLocationBean.chinaPoiName = location.address.province
            chineLocationBean.chinaLatitude = location.latitude
            chineLocationBean.chinaLongitude = location.longitude
            chineLocationBean.chinaAltitude = location.altitude
            if (chinaLocationNChange != null && (type == LocationType.BAI_DU || type == LocationType.ALL)) {
                chinaLocationNChange!!.onReceiveLocation(chineLocationBean)
            }

        }
    }

    //高德定位？
    override fun onLocationChanged(aMapLocation: AMapLocation) {// ? 可能为null,!!强调我这个不为null.但是不保证不为null
        val chineLocationBean = ChineLocationBean()
        chineLocationBean.chinaAdCode = aMapLocation.adCode
        chineLocationBean.chinaAddress = aMapLocation.address
        chineLocationBean.chinaAoiName = aMapLocation.aoiName
        chineLocationBean.chinaCity = aMapLocation.city
        chineLocationBean.chinaCityCode = aMapLocation.cityCode
        chineLocationBean.chinaDistrict = aMapLocation.district
        chineLocationBean.chinaErrorCode = aMapLocation.errorCode
        chineLocationBean.chinaFloor = aMapLocation.floor
        chineLocationBean.chinaRoad = aMapLocation.road
        chineLocationBean.chinaStreet = aMapLocation.street
        chineLocationBean.chinaStreetNumber = aMapLocation.streetNum
        chineLocationBean.chinaProvince = aMapLocation.province
        chineLocationBean.chinaPoiName = aMapLocation.poiName
        chineLocationBean.chinaLatitude = aMapLocation.latitude
        chineLocationBean.chinaLongitude = aMapLocation.longitude
        chineLocationBean.chinaAltitude = aMapLocation.altitude

        if (chinaLocationNChange != null && (type == LocationType.GAO_DE || type == LocationType.ALL)) {
            chinaLocationNChange!!.onReceiveLocation(chineLocationBean)
        }
    }

    //腾讯定位
    inner class MyTencentLocationListener : TencentLocationListener {
        override fun onLocationChanged(location: TencentLocation, i: Int, s: String) {
            if (TencentLocation.ERROR_OK == errorTx) {
                // 定位成功
                Log.e("tenxun", "onReceiveLocation: " + location.latitude + location.address)
                val chineLocationBean = ChineLocationBean( )
                chineLocationBean.chinaAddress = location.address
                chineLocationBean.chinaCity = location.city
                chineLocationBean.chinaCityCode = location.cityCode
                chineLocationBean.chinaDistrict = location.district
                chineLocationBean.chinaErrorCode = 0
                chineLocationBean.chinaFloor = location.indoorBuildingFloor
                chineLocationBean.chinaStreet = location.street
                chineLocationBean.chinaProvince = location.province
                chineLocationBean.chinaLatitude = location.latitude
                chineLocationBean.chinaLongitude = location.longitude
                chineLocationBean.chinaAltitude = location.altitude
                if (chinaLocationNChange != null && (type == LocationType.TEN_XUN || type == LocationType.ALL)) {
                    chinaLocationNChange!!.onReceiveLocation(chineLocationBean)
                }
            } else {
                // 定位失败
            }
        }


        override fun onStatusUpdate(s: String, i: Int, s1: String) {}
    }
}